import {
  AdditiveBlending,
  Camera,
  Material,
  Mesh,
  MeshBasicMaterial,
  MultiplyBlending,
  NoBlending,
  NormalBlending,
  Scene,
  ShaderMaterial,
  WebGLRenderer,
  WebGLRenderTarget,
  ShaderChunk,
} from "three";
import { RenderPass } from "three/examples/jsm/postprocessing/RenderPass.js";

function createShaderMaterial(emissiveIntensity: number) {
  const overrideMaterial = new ShaderMaterial({
    vertexShader: `
      ${ShaderChunk.logdepthbuf_pars_vertex}
      bool isPerspectiveMatrix( mat4 m ) {
        return m[ 2 ][ 3 ] == - 1.0;
      }
      void main() {
        gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
        ${ShaderChunk.logdepthbuf_vertex}
      }
    `,
    fragmentShader: `
      ${ShaderChunk.logdepthbuf_pars_fragment}
      uniform float emissiveIntensity;
      void main() {
        // gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
        gl_FragColor = vec4(emissiveIntensity, emissiveIntensity, emissiveIntensity, 1.0);
        ${ShaderChunk.logdepthbuf_fragment}
      }
    `,
    uniforms: {
      emissiveIntensity: { value: emissiveIntensity || 1.0 },
    },
    depthTest: true,
    depthWrite: true,
    transparent: false,
  });
  return overrideMaterial;
}
const blackMaterial = new MeshBasicMaterial({
  color: 0x000000,
  depthTest: true,
  depthWrite: true,
  transparent: false,
});

export class EmissivePass extends RenderPass {
  materialMap: Record<string, Material> = {};
  oldMaterialMap: Record<string, Material> = {};
  constructor(scene: Scene, camera: Camera) {
    // super(scene, camera, overrideMaterial);
    super(scene, camera);
  }

  render(
    renderer: WebGLRenderer,
    writeBuffer: WebGLRenderTarget,
    readBuffer: WebGLRenderTarget,
    deltaTime: number,
    maskActive: boolean
  ): void {
    this.replaceMaterial();
    super.render(renderer, writeBuffer, readBuffer, deltaTime, maskActive);
    this.restoreMaterial();
  }
  replaceMaterial() {
    this.scene.traverse((item) => {
      if (item instanceof Mesh) {
        if (this.materialMap[item.uuid]) {
          item.material = this.materialMap[item.uuid];
        } else {
          this.oldMaterialMap[item.uuid] = item.material;
          if (
            item.material.emissiveIntensity &&
            item.material.emissive &&
            item.material.emissive.getHex() !== 0x000000
          ) {
            // item.material = createShaderMaterial(
            //   item.material.emissiveIntensity
            // );
            // this.materialMap[item.uuid] = item.material;
          } else {
            item.material = blackMaterial;
            this.materialMap[item.uuid] = blackMaterial;
          }
        }
      }
    });
  }
  restoreMaterial() {
    this.scene.traverse((item) => {
      if (item instanceof Mesh) {
        if (this.oldMaterialMap[item.uuid]) {
          item.material = this.oldMaterialMap[item.uuid];
        }
      }
    });
  }
  dispose(): void {
    super.dispose();
  }
}
